﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Web.UI;
using Shinkansen.Core;

namespace Shinkansen.Web.UI.WebControls
{
    [ParseChildren (true), PersistChildren (false), Bindable (false)]
    public class StaticResourceManager : Control, IStaticResourceManager
    {
        private Collection<JavaScriptInclude> _javaScriptIncludes;
        private Collection<CssInclude> _cssIncludes;

        private HttpCompressionMode _httpCompression = HttpCompressionMode.None;
        private ScriptPlacement _scriptPlacement = ScriptPlacement.Bottom;

        private bool _crunch = false;
        private bool _combine = false;


        /// <summary>
        /// Gets or sets the HTTP compress with.
        /// </summary>
        /// <value>The HTTP compress with.</value>
        public HttpCompressionMode HttpCompressWith
        {
            get { return _httpCompression; }
            set { _httpCompression = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to crunch (minify, etc) these resources.
        /// </summary>
        /// <value><c>true</c> if crunch; otherwise, <c>false</c>.</value>
        public bool Crunch
        {
            get { return _crunch; }
            set { _crunch = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to combine these resources.
        /// </summary>
        /// <value><c>true</c> if combine; otherwise, <c>false</c>.</value>
        public bool Combine
        {
            get { return _combine; }
            set { _combine = value; }
        }

        /// <summary>
        /// Gets or sets the script placement.
        /// </summary>
        /// <value>The script placement.</value>
        public ScriptPlacement ScriptPlacement
        {
            get { return _scriptPlacement; }
            set { _scriptPlacement = value; }
        }

        /// <summary>
        /// Gets a <see cref="T:System.Web.UI.ControlCollection"/> object that represents the child controls for a specified server control in the UI hierarchy.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The collection of child controls for the specified server control.
        /// </returns>
        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls ();
                return base.Controls;
            }
        }

        /// <summary>
        /// Gets the java script.
        /// </summary>
        /// <value>The java script.</value>
        [PersistenceMode (PersistenceMode.InnerProperty)]
        public Collection<JavaScriptInclude> JavaScript
        {
            get { return _javaScriptIncludes ?? (_javaScriptIncludes = new Collection<JavaScriptInclude> ()); }
        }

        /// <summary>
        /// Gets the CSS script.
        /// </summary>
        /// <value>The CSS script.</value>
        [PersistenceMode (PersistenceMode.InnerProperty)]
        public Collection<CssInclude> Css
        {
            get { return _cssIncludes ?? (_cssIncludes = new Collection<CssInclude> ()); }
        }

        /// <summary>
        /// Handles the PreRenderComplete event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void Page_PreRenderComplete (object sender, EventArgs e)
        {
            var options = new ShinkansenOptions
            {
                Crunch = this.Crunch,
                Combine = this.Combine,
                HttpCompressWith = this.HttpCompressWith
            };

            new JavaScriptTagBuilder (options, JavaScript, RegisterJsInclude).Run ();
            new CssTagBuilder (options, Css, RegisterCssLink).Run ();
        }

        /// <summary>
        /// Registers the CSS link.
        /// </summary>
        /// <param name="tag">The tag.</param>
        private void RegisterCssLink (string tag)
        {
            Page.Header.Controls.Add (new LiteralControl (tag));
        }

        /// <summary>
        /// Registers the include.
        /// </summary>
        /// <param name="tag">The tag.</param>
        private void RegisterJsInclude (string tag)
        {
            switch (ScriptPlacement)
            {
                case ScriptPlacement.Top:
                    Page.Header.Controls.Add (new LiteralControl (tag));
                    break;

                case ScriptPlacement.Bottom:
                    Page.ClientScript.RegisterStartupScript (this.GetType (), Guid.NewGuid ().ToString (), tag);
                    break;
            }
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Init"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnInit (EventArgs e)
        {
            base.OnInit (e);
            this.Page.PreRenderComplete += Page_PreRenderComplete;
        }
    }
}